package com.lanhao.aot.elasticsearch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.Conflicts;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.InlineScript;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch._types.Script;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.FuzzyQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhrasePrefixQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhraseQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Operator;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQueryField;
import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType;
import co.elastic.clients.elasticsearch._types.query_dsl.WildcardQuery;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.CreateResponse;
import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest;
import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
import co.elastic.clients.elasticsearch.core.DeleteResponse;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchRequest.Builder;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.UpdateByQueryRequest;
import co.elastic.clients.elasticsearch.core.UpdateByQueryResponse;
import co.elastic.clients.elasticsearch.core.UpdateResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
import co.elastic.clients.elasticsearch.core.search.SourceFilter;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.core.search.TrackHits;
import co.elastic.clients.elasticsearch.indices.CloseIndexResponse;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteAliasResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.elasticsearch.indices.GetIndexResponse;
import co.elastic.clients.elasticsearch.indices.IndexState;
import co.elastic.clients.elasticsearch.indices.OpenResponse;
import co.elastic.clients.elasticsearch.indices.PutAliasResponse;
import co.elastic.clients.elasticsearch.indices.RolloverResponse;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;

public class ElasticsearchUtil {
	private static final Logger LOG = LoggerFactory.getLogger(ElasticsearchUtil.class);
	private static final String SCRIPT_PREFIX = "ctx._source.";
	private static String hostNames = "127.0.0.1:9200";

	public static ElasticsearchClient getElasticsearchClient() {
		String[] hostsplit = hostNames.split(",");
		HttpHost[] httpHostArray = new HttpHost[hostsplit.length];
		for (int i = 0; i < hostsplit.length; i++) {
			String item = hostsplit[i];
			String[] itemSplit = item.split(":");
			httpHostArray[i] = new HttpHost(itemSplit[0], Integer.parseInt(itemSplit[1]), HttpHost.DEFAULT_SCHEME_NAME);
		}
		RestClient restClient = RestClient.builder(httpHostArray).build();
		// 使用Jackson映射器创建传输层
		ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
		// 创建API客户端
		ElasticsearchClient client = new ElasticsearchClient(transport);
		return client;
	}

	/**
	 * 创建索引
	 * 
	 * @param indexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean createIndex(String indexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		CreateIndexResponse response = client.indices().create(c -> c.index(indexName));
		return response.acknowledged();
	}

	/**
	 * 删除索引
	 * 
	 * @param indexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean deleteIndex(String indexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		DeleteIndexResponse response = client.indices().delete(c -> c.index(indexName));
		return response.acknowledged();
	}

	/**
	 * 查询索引状态信息
	 * 
	 * @param indexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static IndexState getIndexState(String indexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		GetIndexResponse response = client.indices().get(c -> c.index(indexName));
		Map<String, IndexState> result = response.result();
		if (MapUtils.isNotEmpty(result)) {
			return result.get(indexName);
		}
		return null;
	}
	
	/**
	 * 索引rollover
	 * @param alias
	 * @param newIndexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean rolloverIndex(String alias, String newIndexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		RolloverResponse response = client.indices().rollover(c -> c.alias(alias).newIndex(newIndexName)
				.conditions(o -> o.maxAge(new Time.Builder().offset(7).build()).maxDocs(100000L).maxSize("5gb")));
		return response.acknowledged();
	}
	
	/**
	 * 关闭索引
	 * @param indexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean closeIndex(String indexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		CloseIndexResponse response = client.indices().close(c -> c.index(Lists.newArrayList(indexName)));
		return response.acknowledged();
	}
	
	/**
	 * 打开索引
	 * @param indexName
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean openIndex(String indexName) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		OpenResponse response = client.indices().open(c -> c.index(Lists.newArrayList(indexName)));
		return response.acknowledged();
	}
	
	/**
	  *   创建别名
	 * @param indexName
	 * @param alias
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean putAlias(String indexName, String alias) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		PutAliasResponse response = client.indices().putAlias(c -> c.index(Lists.newArrayList(indexName)).name(alias));
		return response.acknowledged();
	}
	
	/**
	  *   删除别名
	 * @param indexName
	 * @param alias
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static boolean deleteAlias(String indexName, String alias) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		DeleteAliasResponse response = client.indices().deleteAlias(c -> c.index(Lists.newArrayList(indexName)).name(Lists.newArrayList(alias)));
		return response.acknowledged();
	}

	/**
	 * 插入文档数据，默认不使用自定义ID
	 * 
	 * @param <T>
	 * @param indexName
	 * @param object
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> boolean createDocument(String indexName, T object) throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		IndexResponse response = client.index(e -> e.index(indexName).document(object));
		return Result.Created.equals(response.result());
	}

	/**
	 * 插入文档数据，使用自定义ID
	 * 
	 * @param <T>
	 * @param indexName
	 * @param id
	 * @param object
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> boolean createDocumentWithId(String indexName, String id, T object)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		CreateResponse response = client.create(c -> c.index(indexName).id(id).document(object));
		return Result.Created.equals(response.result());
	}

	/**
	 * 更新文档数据，使用已知业务ID
	 * 
	 * @param <T>
	 * @param indexName
	 * @param id
	 * @param map
	 * @param clazz
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> boolean updateDocumentWithId(String indexName, String id, Map<String, Object> map, Class<T> clazz)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		UpdateResponse<T> response = client.update(c -> c.index(indexName).id(id).doc(map), clazz);
		return Result.Updated.equals(response.result());
	}
	
	/**
	  * 根据查询的结果更新数据
	 * @param <T>
	 * @param reqParam
	 * @param scriptValue 如 age=12 方法内部会自动补全 ctx._source.
	 * @return 更新成功的数量
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> Long updateDocumentByQuery(SearchReqParamDTO reqParam, String indexName, String scriptValue)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		Query.Builder queryBuild = processBuilder(reqParam, new Query.Builder());
		UpdateByQueryResponse response = client
				.updateByQuery(new UpdateByQueryRequest.Builder().index(Lists.newArrayList(indexName)).query(queryBuild.build()).conflicts(Conflicts.Proceed)
						.script(new Script.Builder().inline(new InlineScript.Builder().source(SCRIPT_PREFIX + scriptValue).build()).build())
						.build());
		Long updated = response.updated();
		return updated;
	}

	/**
	 * 删除文档数据，使用业务已知ID
	 * 
	 * @param <T>
	 * @param indexName
	 * @param id
	 * @param map
	 * @param clazz
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public <T> boolean deleteDocumentWithId(String indexName, String id, Map<String, Object> map, Class<T> clazz)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		DeleteResponse response = client.delete(c -> c.index(indexName).id(id));
		return Result.Deleted.equals(response.result());
	}
	
	/**
	 * 根据查询结果删除数据
	 * @param <T>
	 * @param indexName
	 * @param id
	 * @param map
	 * @param clazz
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public <T> Long deleteDocumentByQuery(String indexName, SearchReqParamDTO reqParam)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		Query.Builder queryBuild = processBuilder(reqParam, new Query.Builder());
		DeleteByQueryResponse response = client.deleteByQuery(new DeleteByQueryRequest.Builder().index(Lists.newArrayList(indexName)).query(queryBuild.build()).conflicts(Conflicts.Proceed).build());
		return response.deleted();
	}

	/**
	 * 批量插入数据
	 * 
	 * @param <T>
	 * @param indexName
	 * @param docList
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> boolean createBathDocument(String indexName, List<T> docList)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		List<BulkOperation> bathOperateList = new ArrayList<>();
		for (int i = 0; i < docList.size(); i++) {
			T o = docList.get(i);
			bathOperateList.add(new BulkOperation.Builder().create(d -> d.index(indexName).document(o)).build());
		}
		BulkResponse response = client.bulk(e -> e.index(indexName).operations(bathOperateList));
		// {"errors":false,"items":[{"create":{"_id":"nT_g-oEBHKfZi_6mBxiL","_index":"data_model","status":201,"_primary_term":1,"result":"created","_seq_no":3,"_shards":{"failed":0.0,"successful":1.0,"total":2.0},"_type":"_doc","_version":1}},{"create":{"_id":"nj_g-oEBHKfZi_6mBxiL","_index":"data_model","status":201,"_primary_term":1,"result":"created","_seq_no":4,"_shards":{"failed":0.0,"successful":1.0,"total":2.0},"_type":"_doc","_version":1}}],"took":12}
		LOG.info("批量创建文档结果response={}", response.toString());
		Boolean errors = response.errors();
		
		return !errors;
	}

	/**
	 * 查询索引下全部数据
	 * 
	 * @param <T>
	 * @param indexName
	 * @param clazz
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> List<T> queryAllIndexDocument(String indexName, Class<T> clazz)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
//		SearchResponse<T> response = client.search(c -> c.index(indexName).query(q -> q.matchAll(m -> m)), clazz);
		SearchRequest searchRequest = getSearchRequest(SearchReqParamDTO.matchAllSearchParam(indexName));
		SearchResponse<T> response = client.search(searchRequest, clazz);
		HitsMetadata<T> hitsMetadata = response.hits();
		List<Hit<T>> hits = hitsMetadata.hits();
		TotalHits total = hitsMetadata.total();
		long value = total.value();
		LOG.info("本次查询的全部记录数：{}", value);
		if (CollectionUtils.isNotEmpty(hits)) {
			List<T> dataList = new ArrayList<>();
			for (Hit<T> hit : hits) {
				dataList.add(hit.source());
			}
			return dataList;
		}
		return null;
	}

	/**
	 * 分页查询索引下全部文档
	 * 
	 * @param <T>
	 * @param indexName
	 * @param pageNo
	 * @param size
	 * @param clazz
	 * @return
	 * @throws ElasticsearchException
	 * @throws IOException
	 */
	public static <T> List<T> conditionQueryDocument(SearchReqParamDTO searchParam, Class<T> clazz)
			throws ElasticsearchException, IOException {
		ElasticsearchClient client = getElasticsearchClient();
		SearchRequest searchRequest = getSearchRequest(searchParam);
		SearchResponse<T> response = client.search(searchRequest, clazz);
		HitsMetadata<T> hitsMetadata = response.hits();
		List<Hit<T>> hits = hitsMetadata.hits();
		TotalHits total = hitsMetadata.total();
		long value = total.value();
		LOG.info("本次查询的全部记录数：{}", value);
		if (CollectionUtils.isNotEmpty(hits)) {
			List<T> dataList = new ArrayList<>();
			for (Hit<T> hit : hits) {
				dataList.add(hit.source());
			}
			return dataList;
		}
		return null;
	}

	/**
	 * 获取查询请求封装对象
	 * 
	 * @return
	 */
	public static SearchRequest getSearchRequest(SearchReqParamDTO reqParam) {
		Builder builder = new SearchRequest.Builder();
		/**
		 * 设置索引名称
		 */
		builder.index(Lists.newArrayList(reqParam.getIndexName()));
		Query.Builder queryBuild = processBuilder(reqParam, new Query.Builder());
		builder.query(queryBuild.build());
		// 从 Elasticsearch 7.0之后，为了提高搜索的性能，在 hits 字段中返回的文档数有时不是最精确的数值，Elasticsearch 7.x在查询时，必须加上track_total_hits，不然就只显示10000
		builder.trackTotalHits(new TrackHits.Builder().enabled(true).build());
		/**
		 * 设置分组信息
		 */
		Pair<String, Aggregation> aggregations = reqParam.getAggregations();
		if (aggregations != null) {
			builder.aggregations(aggregations.getKey(), aggregations.getValue());
		}
		
		/**
		 * 设置分页信息
		 */
		Pair<Integer, Integer> pagination = reqParam.getPagination();
		if (pagination != null) {
			Integer pageNo = pagination.getLeft();
			Integer pageSize = pagination.getRight();
			builder.from((pageNo - 1) * pageSize);
			builder.size(pageSize);
		}
		
		/**
		 * 设置查询返回字段
		 */
		List<String> includes = reqParam.getIncludes();
		List<String> excludes = reqParam.getExcludes();
		if (CollectionUtils.isNotEmpty(includes) || CollectionUtils.isNotEmpty(excludes)) {
			SourceFilter.Builder sourceFilterBuilder = new SourceFilter.Builder();
			if (CollectionUtils.isNotEmpty(includes)) {
				sourceFilterBuilder.includes(includes);
			}
			if (CollectionUtils.isNotEmpty(excludes)) {
				sourceFilterBuilder.includes(excludes);
			}
			builder.source(new SourceConfig.Builder().filter(sourceFilterBuilder.build()).build());
		}
		/**
		 * 设置查询排序信息
		 */
		List<Pair<String, String>> sortFields = reqParam.getSortFields();
		if (CollectionUtils.isNotEmpty(sortFields)) {
			List<SortOptions> sortOptions = new ArrayList<>();
			for (Pair<String, String> pair : sortFields) {
				sortOptions.add(new SortOptions.Builder().field(
						new FieldSort.Builder().field(pair.getLeft()).order(SortOrder.valueOf(pair.getRight())).build())
						.build());
			}
			builder.sort(sortOptions);
		}

		SearchRequest searchRequest = builder.build();
		return searchRequest;
	}
	
	/**
	 * 处理Builder查询信息
	 * @return
	 */
	public static Query.Builder processBuilder(SearchReqParamDTO reqParam, Query.Builder queryBuild) {
		SearchMode searchMode = reqParam.getSearchMode();
		/**
		 * 名称 				作用 
		 * match_all   		match_all	可以用于查询全部信息
		 * match 			执行查询时，搜索的词会被分词器分词，例如：我芦本伟没有开挂 ----> 我，卢本伟，没有，开挂
		 * matchPhrase 		短语的形式查询，也就是不会被分词，例如：给阿姨倒一杯卡布奇诺 ----> 给阿姨倒一杯卡布奇诺 
		 * term 			term是ES中的精准查询，不会参与ES分词查询
		 * terms 			terms查询是term的扩展，可以支持多个vlaue匹配，只需要一个匹配就可以了
		 * multi_match 		multi_match是多字段进行匹配查询
		 * fuzzy			fuzzy查询可以用于纠正去拼写的问题（模糊查询）
		 * wildcard			通配符查询允许我们指定一个模式来匹配，而不需要指定完整的trem，匹配的方式类似于match的分词匹配查询。?将会匹配如何字符；*将会匹配零个或者多个字符。
		 * bool 			bool查询本身没有查询功能，而是基于逻辑值使用前面几种查询方式进行组合查询，体内方法-----> (must，must_not，should)
		 * fuzzy 			fuzzy查询可以用于纠正去拼写的问题（模糊查询）
		 **/
		String field = StringUtils.EMPTY;
		List<String> fieldList = reqParam.getFieldList();
		if (CollectionUtils.isNotEmpty(fieldList)) {
			field = fieldList.get(0);
		}
		List<String> valueList = reqParam.getValueList();

		String queryValue = StringUtils.EMPTY;
		if (CollectionUtils.isNotEmpty(valueList)) {
			queryValue = valueList.get(0);
		}
		switch (searchMode) {
			case MATCH_ALL:
				queryBuild.matchAll(new MatchAllQuery.Builder().build());  // √
				break;
			case MATCH:
				// 在使用matchQuery等时，在执行查询时，搜索的词会被分词器分词 match query搜索的时候，首先会解析查询字符串，进行分词，然后查询
				queryBuild.match(new MatchQuery.Builder().field(field).query(queryValue).build());
				break;
			case MATCH_PHRASE:
				// 使用matchPhraseQuery时，不会被分词器分词，而是直接以一个短语的形式查询
				queryBuild.matchPhrase(new MatchPhraseQuery.Builder().field(field).query(queryValue).build());
				break;
			case MATCH_PHRASE_PREFIX:
				// 使用match_phrase_prefix进行搜索，它返回的结果包含所提供文字的顺序，并严格按照所给的顺序。
				MatchPhrasePrefixQuery.Builder matchPhrasePrefixBuilder = new MatchPhrasePrefixQuery.Builder().field(field).query(queryValue);
				// slop 每2个单词之间最多可以出现的单词数
				Integer slop = reqParam.getSlop();
				if(slop != null) {
					matchPhrasePrefixBuilder.slop(slop);
				}
				queryBuild.matchPhrasePrefix(matchPhrasePrefixBuilder.build());
				break;
			case MULTI_MATCH:
				// 多field  一个value
				MultiMatchQuery.Builder multiMatchQueryBuilder = new MultiMatchQuery.Builder();
				multiMatchQueryBuilder.fields(fieldList).query(queryValue);
				TextQueryType textQueryType = reqParam.getTextQueryType();
				if (textQueryType != null) {
					multiMatchQueryBuilder.type(textQueryType); // 默认best_fields
				}
				Operator operator = reqParam.getOperator();
				if (operator != null) {
					multiMatchQueryBuilder.operator(operator);
				}
				queryBuild.multiMatch(multiMatchQueryBuilder.build());
				break;
			case RANGE:
				RangeQuery.Builder rangeBuilder = new RangeQuery.Builder().field(field);
				Integer rangeType = reqParam.getRangeType();
				Object rangeStart = reqParam.getRangeStart();
				Object rangeEnd = reqParam.getRangeEnd();
				switch (rangeType) {
					case 0:
						rangeBuilder.gte(JsonData.of(rangeStart)).lte(JsonData.of(rangeEnd));
						break;
					case 1:
						rangeBuilder.gt(JsonData.of(rangeStart)).lte(JsonData.of(rangeEnd));				
						break;
					case 2:
						rangeBuilder.gte(JsonData.of(rangeStart)).lt(JsonData.of(rangeEnd));
						break;
					case 3:
						rangeBuilder.gt(JsonData.of(rangeStart)).lt(JsonData.of(rangeEnd));
						break;
					case 4:
						rangeBuilder.gt(JsonData.of(rangeStart));
						break;
					case 5:
						rangeBuilder.gte(JsonData.of(rangeStart));
					case 6:
						rangeBuilder.lt(JsonData.of(rangeEnd));
						break;
					case 7:
						rangeBuilder.lte(JsonData.of(rangeEnd));
						break;
					default:
						break;
				}
				queryBuild.range(rangeBuilder.build());
				break;
			case TERM:
				// 如果使用term查询，要确保字段是no analyzed的，建索引的时候要注意，输入的查询内容是什么，就会按照什么去查询，并不会解析查询内容及对它分词
				queryBuild.term(new TermQuery.Builder().field(field).value(queryValue).build());
				break;
			case TERMS:
				// 1个field  多value
				// 如果使用term查询，要确保字段是no analyzed的，建索引的时候要注意，输入的查询内容是什么，就会按照什么去查询，并不会解析查询内容及对它分词
				TermsQuery.Builder termsBuilder = new TermsQuery.Builder().field(field);
				TermsQueryField.Builder termsQueryFieldBuilder = new TermsQueryField.Builder();
				if (CollectionUtils.isNotEmpty(valueList)) {
					List<FieldValue> fieldValueList = valueList.stream().map(v -> new FieldValue.Builder().stringValue(v).build()).collect(Collectors.toList());
					termsQueryFieldBuilder.value(fieldValueList);
				}
				termsBuilder.terms(termsQueryFieldBuilder.build());
				queryBuild.terms(termsBuilder.build());
				break;
			case FUZZY:
				FuzzyQuery.Builder fuzzyBuilder = new FuzzyQuery.Builder().field(field).value(queryValue);
				Integer prefixLength = reqParam.getPrefixLength();
				if(prefixLength != null) {
					fuzzyBuilder.prefixLength(prefixLength);
				}
				String fuzziness = reqParam.getFuzziness();
				if(StringUtils.isNotBlank(fuzziness)) {
					fuzzyBuilder.fuzziness(fuzziness);
				}
				queryBuild.fuzzy(fuzzyBuilder.build());
				break;
			case WILDCARD:
				queryBuild.wildcard(new WildcardQuery.Builder().field(field).wildcard(queryValue).build());
				break;
			case BOOL:
				BoolQuery.Builder boolBuilder = new BoolQuery.Builder();
				List<BoolQueryParamDTO> boolQueryParamList = reqParam.getBoolQueryParamList();
				for (BoolQueryParamDTO boolQueryParamDTO : boolQueryParamList) {
					List<SearchReqParamDTO> boolSearchParamList = boolQueryParamDTO.getBoolSearchParamList();
					List<Query> boolQueryList = new ArrayList<Query>();
					for (SearchReqParamDTO boolSearchParam : boolSearchParamList) {
						Query.Builder boolQueryBuilder = processBuilder(boolSearchParam, new Query.Builder());
						boolQueryList.add(boolQueryBuilder.build());
					}
					SearchMode boolMode = boolQueryParamDTO.getBoolMode();
					switch (boolMode) {
						case MUST:
							boolBuilder.must(boolQueryList);
							break;
						case MUST_NOT:
							boolBuilder.mustNot(boolQueryList);
							break;
						case SHOULD:
							boolBuilder.should(boolQueryList);
							break;
						case FILTER:
							boolBuilder.filter(boolQueryList);
							break;
						default:
							break;
					}
				}
				queryBuild.bool(boolBuilder.build());
				break;
			case INTERVALS:
				// TODO 待补充
				// queryBuild.intervals(new IntervalsQuery.Builder().build());
				break;
			case BOOSTING:
				// queryBuild.boosting(new BoostingQuery.Builder().build());
				break;
			default:
				break;
		}
		
		return queryBuild;
	}

}
